#include "fdcan_reg.h"
#include "conversion.h"



p_fdcan_reg_list_s p_fdcan_reg_list_head = NULL;
p_fdcan_reg_list_s p_fdcan_reg_list_tail = NULL;
uint16_t fdcan_reg_list_num = 0;


static void Reg_Set_Bit(uint8_t *p_data, uint8_t offset, uint8_t val)
{
    const uint8_t temp = 1 << offset;
    if (val != 0)
    {
        *p_data |= temp;
    }
    else
    {
        *p_data &= ~temp;
    }
}


static uint8_t Reg_Get_Bit(uint8_t data, uint8_t offset)
{
    const uint8_t temp1 = 1 << offset;
    const uint8_t temp2 = data & temp1;
#if 0
    return temp2;
#else
    return temp2 ? 1 : 0;
#endif
}



static void Reg_Clean(p_fdcan_reg_list_s *p_list)
{
    p_fdcan_reg_list_s p_temp;

    while (p_list != NULL && *p_list != NULL)
    {
        p_temp = (*p_list)->next;
        free(*p_list);
        *p_list = p_temp;
    }
    *p_list = NULL;
    fdcan_reg_list_num = 0;
}


void Reg_Init()
{
    Reg_Clean(&p_fdcan_reg_list_head);
}


static void Reg_Add(char *p_str)
{
    const p_fdcan_reg_list_s p_list = (p_fdcan_reg_list_s)malloc(sizeof(fdcan_reg_list_s));
    if (p_list == NULL)
    {
        print("T set add null err!!!\r\n");
        return;
    }
	p_list->next = NULL;

    if (Conv_Str_Int(&p_str, (uint32_t *)&p_list->reg.inte) != 0)
    {
        print("T set add str to int err\r\n");
        free(p_list);
        return;
    }

    if (!(*p_str >= '0' && *p_str <= '9'))
    {
        do
        {
            switch (*p_str)
            {
            case 'E':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_EN, 1);
                break;
            case 'A':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_ACC, 1);
                break;
            case 'L':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_NUM_LIMI, 1);
				p_str++;
				Conv_Str_Int(&p_str, &p_list->reg.cnt);
                break;
            case 'D':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_DEL, 1);
                break;
            case 'e':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_EN, 0);
                break;
            case 'a':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_ACC, 0);
                break;
            case 'l':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_NUM_LIMI, 0);
                break;
            case 'd':
                Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_DEL, 0);
                break;
            default:
                print("T set add s err\r\n");
                free(p_list);
                return;
            }
			p_str++;
        } while (*p_str != ' ' && *p_str != '\r' && *p_str != '\n');
		p_str++;
    }

    if (Conv_Ascii_To_Hex((uint8_t *)p_str, &p_list->reg.buf) != 0)
    {
        print("T set add buf err\r\n");
        free(p_list);
        return;
    }

    if (p_fdcan_reg_list_tail == NULL)
    {
        p_fdcan_reg_list_head = p_fdcan_reg_list_tail = p_list;
    }
    else
    {
        p_fdcan_reg_list_tail->next = p_list;
        p_fdcan_reg_list_tail = p_fdcan_reg_list_tail->next;
    }
    fdcan_reg_list_num++;
	
	print("T set all ok\r\n");
}


static void Reg_Del_Int(uint16_t index)
{
    p_fdcan_reg_list_s p_list1 = p_fdcan_reg_list_head;
    
    if (index == 1)
    {
        p_fdcan_reg_list_head = p_list1->next;
        free(p_list1);
    }
    else
    {
        p_fdcan_reg_list_s p_list2 = NULL;
        for (uint8_t i = 1; i < index; i++)
        {
            p_list2 = p_list1;
            p_list1 = p_list1->next;
        }

        p_list2->next = p_list1->next;
        free(p_list1);
    }

    fdcan_reg_list_num--;
    print("T set del ok\r\n");
}


static void Reg_Del_Str(char *p_str)
{
    uint32_t index = 0;
    
    if (Conv_Str_Int(&p_str, &index) != 0 || index > fdcan_reg_list_num || p_fdcan_reg_list_head == NULL)
    {
        print("T set del index err\r\n");
        return;
    }

    Reg_Del_Int(index);
}


static void Reg_Get(char *p_str)
{   
    char tdata[200] = {0};

    if (strncmp(p_str, "set", 3) == 0)
    {
        print("T get set %d\r\n", fdcan_reg_list_num);
        if (fdcan_reg_list_num == 0)
        {
            return;
        }
        HAL_Delay(1);

        p_fdcan_reg_list_s p_list = p_fdcan_reg_list_head;
        
        memcpy(tdata, "T get ", 6);
        for (uint8_t i = 1; i <= fdcan_reg_list_num; i++)
        {
            const uint8_t len2 = snprintf(tdata + 6, sizeof(tdata) - 6, "%X ", p_list->reg.inte);
            const uint16_t len = Conv_Hex_To_Ascii(&p_list->reg.buf, (uint8_t *)&tdata[6 + len2]);
            Usart_Send((uint8_t *)tdata, len + len2 + 6);
            p_list = p_list->next;
			HAL_Delay(1);
        }

        return;
    }


    print("T get err\r\n");
}


static void Reg_Set(char *p_str)
{
    if (strncmp(p_str, "add", 3) == 0)
    {
        p_str += 4;
        Reg_Add(p_str);

        return;
    }
    else if (strncmp(p_str, "del", 3) == 0)
    {
        p_str += 4;
        Reg_Del_Str(p_str);

        return;
    }
    else if (strncmp(p_str, "clean", 5) == 0)
    {
        p_str += 5;
        Reg_Clean(&p_fdcan_reg_list_head);
        print("T set clean ok\r\n");

        return;
    }

    print("T set err\r\n");
}


void Reg_Handle(char *p_str)
{
    if (p_str == NULL)
    {
        print("T err\r\n");
        return;
    }

    if (strncmp(p_str, "get", 3) == 0)
    {
        p_str += 4;
        Reg_Get(p_str);
    }
    else if (strncmp(p_str, "set", 3) == 0)
    {
        p_str += 4;
        Reg_Set(p_str);
    }
}


void Reg_Run()
{
    static uint32_t tick_1ms = 0;

    if (HAL_GetTick() - tick_1ms >= 1)
    {
		tick_1ms = HAL_GetTick();
        p_fdcan_reg_list_s p_list = p_fdcan_reg_list_head;
        uint8_t list_num = 0;

        while (p_list != NULL)
        {
            if (Reg_Get_Bit(p_list->reg.flag, REG_OFFSET_EN) != 0 && HAL_GetTick() - p_list->reg.old_time >= p_list->reg.inte)
            {
                list_num++;
                p_list->reg.old_time = HAL_GetTick();
                Fdcan_Port_Send(&p_list->reg.buf, Reg_Get_Bit(p_list->reg.flag, REG_OFFSET_ACC));
                if (Reg_Get_Bit(p_list->reg.flag, REG_OFFSET_NUM_LIMI) != 0 && --p_list->reg.cnt == 0)
                {
                    if (Reg_Get_Bit(p_list->reg.flag, REG_OFFSET_DEL) != 0)
                    {
                        Reg_Del_Int(list_num);
                    }
                    else
                    {
                        Reg_Set_Bit(&p_list->reg.flag, REG_OFFSET_EN, 0);
                    }
                }
            }
            p_list = p_list->next;
        }
    }
}
